home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp95 / freyja13.exe / lha / CALC.C < prev    next >
C/C++ Source or Header  |  1992-03-22  |  55KB  |  2,380 lines

  1. /* CALC.C -- RPN Calculator
  2.  
  3.     Written March 1991 by Craig A. Finseth
  4.     Copyright 1991 by Craig A. Finseth
  5. */
  6.  
  7. #include "freyja.h"
  8. #include <math.h>
  9. #if defined(MSDOS)
  10. #include <time.h>
  11. #endif
  12.  
  13.     /* ---------- configuration ---------- */
  14.  
  15. #define REGCOUNT    32    /* number of user registers */
  16. #define BINSIZE        32    /* max size of a binary in bits */
  17.  
  18. #define WORKSIZE    20    /* amount of "working input" space */
  19.  
  20. #define SYS_ALPHA    "%alpha%"
  21. #define SYS_CALC    "%calc%"
  22. #define SYS_PRINT    "%print%"
  23. #define SYS_TRACE    "%trace%"
  24.  
  25.     /* ---------- commands ---------- */
  26.  
  27. enum CMDS { CM_ABS, CM_ACOS, CM_ADD, CM_AND, CM_ASIN, CM_ATAN, CM_B,
  28. CM_CF, CM_CLRG, CM_CLST, CM_CLSUM, CM_CLX, CM_COS, CM_D, CM_DATE,
  29. CM_DATEM, CM_DATEP, CM_DDAYS, CM_DEC, CM_DEFAULT, CM_DEG,
  30. CM_DIGSEPOFF, CM_DIGSEPON, CM_DIV, CM_DMY, CM_DOW, CM_DTOR, CM_ENTER,
  31. CM_EXP, CM_EXPM1, CM_FACT, CM_FRC, CM_GRAD, CM_H, CM_HELP, CM_HMS,
  32. CM_HMSM, CM_HMSP, CM_HR, CM_INT, CM_INV, CM_LASTX, CM_LN, CM_LNP1,
  33. CM_LOG, CM_MDY, CM_MEAN, CM_MEMLOAD, CM_MEMSAVE, CM_MEMSUM,
  34. CM_MEMVIEW, CM_MOD, CM_MUL, CM_NEG, CM_NOT, CM_NULL, CM_NUM, CM_O,
  35. CM_OCT, CM_OR, CM_PCT, CM_PCTCH, CM_PCTTOT, CM_PI, CM_PTOR, CM_PWR,
  36. CM_RAD, CM_RADIXC, CM_RADIXD, CM_RCL, CM_RDN, CM_RTOD, CM_RTOP,
  37. CM_RUP, CM_SDEV, CM_SF, CM_SIGN, CM_SIN, CM_SQ, CM_SQRT, CM_STD,
  38. CM_STO, CM_SUB, CM_SUMADD, CM_SUMGET, CM_SUMSET, CM_SUMSUB, CM_SWAP,
  39. CM_SWAPR, CM_TAN, CM_TENX, CM_TIME, CM_TRACEOFF, CM_TRACEON, CM_WSIZE,
  40. CM_WSIZEQ, CM_X360, CM_X365, CM_XACTUAL, CM_XCAL, CM_XCALD, CM_XEQ,
  41. CM_XOR, CM_XRND, CM_XROOT, CM_LAST };
  42.  
  43.     /* ---------- command list ---------- */
  44.  
  45. struct command {
  46.     enum CMDS cmd;        /* command id */
  47.     char *name;        /* command name */
  48.     char desc[11];        /* command descriptor:
  49.         desc[0], command suffix
  50.             SP    none
  51.             'B'    buffer name
  52.             'L'    label
  53.             'N'    number
  54.             'P'    oPerator or register
  55.             'R'    register
  56.         desc[1], number of arguments dropped off the stack
  57.             '0' zero, '1', one, '2' two, '3' three, '4' four
  58.         desc[2345], argument descriptors
  59.             SP    no argument for this entry
  60.             '*'    any type
  61.             'B'    coerce to binary
  62.             'R'    coerce to real
  63.         desc[6], number of results pushed to stack
  64.             '0' zero, '1', one, '2' two, '3' three, '4' four
  65.         desc[7], last X usage
  66.             SP    not affected
  67.             'L'    last x register is updated
  68.         desc[8], stack lift
  69.             SP    disabled
  70.             'E'    enabled
  71.         desc[9], trace info
  72.             SP    nothing special
  73.             R    register
  74.             S    summation
  75.         desc[10] NUL */
  76.  
  77.     char *help;        /* help string */
  78.     };
  79.  
  80. #define NUMCMDS        (sizeof(commands) / sizeof(commands[0]))
  81.  
  82.     /* base commands */
  83. static struct command commands[] = {
  84. { CM_NUM,    "",    " 0    1 E ",    "enter a number" },
  85. { CM_PCT,    "%",    " 2RR  2LE ",    "percent" },
  86. { CM_PCTCH,    "%CH",    " 2RR  1LE ",    "percent change" },
  87. { CM_PCTTOT,    "%TOT",    " 2RR  2LE ",    "percent of total" },
  88. { CM_MUL,    "*",    " 2**  1LE ",    "multiply" },
  89. { CM_ADD,    "+",    " 2**  1LE ",    "add" },
  90. { CM_SUB,    "-",    " 2**  1LE ",    "subtract" },
  91. { CM_DIV,    "/",    " 2RR  1LE ",    "divide" },
  92. { CM_INV,    "1/X",    " 1R   1LE ",    "inverse (use INV)" },
  93. { CM_TENX,    "10^X",    " 2RR  1LE ",    "common exponent (use ALOG)" },
  94. { CM_RCL,    "<",    "P0    1 ER",    "recall" },
  95. { CM_STO,    ">",    "P1*   1 ER",    "store" },
  96. { CM_ABS,    "ABS",    " 1R   1LE ",    "absolute value" },
  97. { CM_ACOS,    "ACOS",    " 1R   1LE ",    "arc cosine" },
  98. { CM_TENX,    "ALOG",    " 2RR  1LE ",    "common exponent" },
  99. { CM_AND,    "AND",    " 2BB  1LE ",    "bitwise and" },
  100. { CM_ASIN,    "ASIN",    " 1R   1LE ",    "arc sin" },
  101. { CM_ATAN,    "ATAN",    " 1R   1LE ",    "arc tangenet" },
  102. { CM_B,        "B",    " 0    0 E ",    "set binary mode" },
  103. { CM_CF,    "CF",    "N0    0 E ",    "clear flag" },
  104. { CM_CLRG,    "CLRG",    " 0    0 E ",    "clear registers" },
  105. { CM_CLST,    "CLST",    " 0    0 E ",    "clear stack" },
  106. { CM_CLX,    "CLX",    " 0    0 D ",    "clear x" },
  107. { CM_CLSUM,    "CL\\GS"," 0    0 ES",    "clear summation" },
  108. { CM_CLSUM,    "CL~",    " 0    0 ES",    "clear summation" },
  109. { CM_COS,    "COS",    " 1R   1LE ",    "cosine" },
  110. { CM_D,        "D",    " 0    0 E ",    "set decimal mode" },
  111. { CM_DTOR,    "D-R",    " 1R   1LE ",    "convert degrees to radians" },
  112. { CM_DATEM,    "DATE-"," 2BR  1LE ",    "subtract days from date" },
  113. { CM_DATEP,    "DATE+"," 2BR  1LE ",    "add days to date" },
  114. { CM_DATE,    "DATE",    " 0    1 E ",    "return the current date" },
  115. { CM_DDAYS,    "DDAYS"," 2RR  1LE ",    "compute days between dates" },
  116. { CM_DEC,    "DEC",    " 1*   1LE ",    "convert octal to decimal" },
  117. { CM_DEFAULT,    "DEFAULT"," 0    0 E ",    "restore default settings" },
  118. { CM_DEG,    "DEG",    " 0    0 E ",    "set degrees mode" },
  119. { CM_DIGSEPOFF,    "DIGSEPOFF"," 0    0 E ","set digit sep to not display" },
  120. { CM_DIGSEPON,    "DIGSEPON"," 0    0 E ","set digit sep to display" },
  121. { CM_DOW,    "DOW",    " 1R   1 E ",    "figure a date's day of the week" },
  122. { CM_DMY,    "DMY",    " 0    0 E ",    "set D.MY mode" },
  123. { CM_ENTER,    "ENTER^"," 1*   2 D ",    "enter" },
  124. { CM_EXP,    "E^X",    " 1R   1LE ",    "natural exponent" },
  125. { CM_EXPM1,    "E^X-1"," 1R   1LE ",    "natural exponent - 1" },
  126. { CM_FACT,    "FACT",    " 1R   1LE ",    "factorial" },
  127. { CM_FRC,    "FRC",    " 1R   1LE ",    "fractional part" },
  128. { CM_GRAD,    "GRAD",    " 0    0 E ",    "set grads mode" },
  129. { CM_H,        "H",    " 0    0 E ",    "set hexadecimal mode" },
  130. { CM_HELP,    "HELP",    " 0    0 E ",    "help" },
  131. { CM_HMSM,    "HMS-",    " 2RR  1LE ",    "subtract two times in H.MS notation"},
  132. { CM_HMSP,    "HMS+",    " 2RR  1LE ",    "add two times in H.MS notation" },
  133. { CM_HMS,    "HMS",    " 1R   1LE ",    "convert decimal hours to H.MS" },
  134. { CM_HR,    "HR",    " 1R   1LE ",    "convert H.MS to decimal hours" },
  135. { CM_INT,    "INT",    " 1R   1LE ",    "integer part" },
  136. { CM_INV,    "INV",    " 1R   1LE ",    "inverse" },
  137. { CM_LASTX,    "L",    " 0    1 E ",    "recall last x" },
  138. { CM_LASTX,    "LASTX"," 0    1 E ",    "recall last x" },
  139. { CM_LN,    "LN",    " 1R   1LE ",    "natural logarithm" },
  140. { CM_LNP1,    "LN1+X"," 1R   1LE ",    "natural logarithm + 1" },
  141. { CM_LOG,    "LOG",    " 1R   1LE ",    "common logarithm" },
  142. { CM_MDY,    "MDY",    " 0    0 E ",    "set M.DY mode" },
  143. { CM_MEAN,    "MEAN",    " 0    2 ES",    "average" },
  144. { CM_MEMLOAD,    "MEMLOAD"," 0    0 E ",    "load calculator memory" },
  145. { CM_MEMSAVE,    "MEMSAVE"," 0    0 E ",    "save calculator memory" },
  146. { CM_MEMVIEW,    "MEMVIEW"," 0    0 E ",    "view calculator memory" },
  147. { CM_MEMSUM,    "MEM\\GS"," 0    0 E ",    "view summation registers" },
  148. { CM_MEMSUM,    "MEM~",    " 0    0 E ",    "view summation registers" },
  149. { CM_MOD,    "MOD",    " 2RR  1LE ",    "modulus" },
  150. { CM_NEG,    "NEG",    " 1R   1LE ",    "negate" },
  151. { CM_NOT,    "NOT",    " 1B   1LE ",    "bitwise not" },
  152. { CM_NULL,    "NULL",    " 0    0 E ",    "no op" },
  153. { CM_O,        "O",    " 0    0 E ",    "set octal mode" },
  154. { CM_OCT,    "OCT",    " 1*   1LE ",    "convert decimal to octal" },
  155. { CM_OR,    "OR",    " 2BB  1LE ",    "bitwise or" },
  156. { CM_PTOR,    "P-R",    " 2RR  2LE ",    "convert polar to rectangular" },
  157. { CM_PI,    "PI",    " 0    1 E ",    "constant pi" },
  158. { CM_RDN,    "R",    " 0    0 E ",    "roll down" },
  159. { CM_RTOD,    "R-D",    " 1R   1LE ",    "convert radians to degrees" },
  160. { CM_RTOP,    "R-P",    " 2RR  2LE ",    "convert rectangular to polar" },
  161. { CM_RAD,    "RAD",    " 0    0 E ",    "set radians mode" },
  162. { CM_RADIXC,    "RADIX,"," 0    0 E ",    "set radix mark to ," },
  163. { CM_RADIXD,    "RADIX."," 0    0 E ",    "set radix mark to ." },
  164. { CM_RCL,    "RCL",    "P0    1 ER",    "recall" },
  165. { CM_RDN,    "RDN",    " 0    0 E ",    "roll down" },
  166. { CM_RUP,    "R^",    " 0    0 E ",    "roll up" },
  167. { CM_SWAP,    "S",    " 2**  2 E ",    "swap: x<>y" },
  168. { CM_SDEV,    "SDEV",    " 0    2 ES",    "standard deviation" },
  169. { CM_SIGN,    "SIGN",    " 1R   1LE ",    "sign of number" },
  170. { CM_SIN,    "SIN",    " 1R   1LE ",    "sin" },
  171. { CM_SF,    "SF",    "N0    0 E ",    "set flag" },
  172. { CM_SQRT,    "SQRT",    " 1R   1LE ",    "square root" },
  173. { CM_STD,    "STD",    " 0    0 E ",    "set display all digits notation" },
  174. { CM_STO,    "STO",    "P1*   1 ER",    "store" },
  175. { CM_STO,    "ST",    "P1*   1 ER",    "store" },
  176. { CM_ENTER,    "T",    " 1*   2 D ",    "enter" },
  177. { CM_TAN,    "TAN",    " 1R   1LE ",    "tangent" },
  178. { CM_TIME,    "TIME",    " 0    1 E ",    "return the current time" },
  179. { CM_TRACEOFF,    "TRACEOFF"," 0    0 E ","set trace mode off" },
  180. { CM_TRACEON,    "TRACEON"," 0    0 E ",    "set trace mode on" },
  181. { CM_WSIZE,    "WSIZE"," 1B   0 E ",    "set word size" },
  182. { CM_WSIZEQ,    "WSIZE?"," 0    1 E ",    "get word size" },
  183. { CM_X360,    "X360",    " 0    0 E ",    "set mode to 360 day calendar" },
  184. { CM_X365,    "X365",    " 0    0 E ",    "set mode to 365 day calendar" },
  185. { CM_SWAPR,    "X<>",    "R1*   1 ER",    "swap with" },
  186. { CM_XACTUAL,    "XACTUAL"," 0    0 E ",    "set mode to actual calendar" },
  187. { CM_XCAL,    "XCAL",    " 1R   0LE ",    "generate a calendar for the date" },
  188. { CM_XCALD,    "XCALD"," 1B   0LE ",    "move the calendar by X months" },
  189. { CM_XEQ,    "XEQ",    "B0    0 E ",    "execute a buffer" },
  190. { CM_XOR,    "XOR",    " 2BB  1LE ",    "bitwise xor" },
  191. { CM_XRND,    "XRND",    " 2BR  1LE ",    "round Y to X decimal places" },
  192. { CM_XROOT,    "XROOT"," 2RR  1LE ",    "xth root of y" },
  193. { CM_SQ,    "X^2",    " 1*   1LE ",    "square" },
  194. { CM_PWR,    "Y^X",    " 2RR  1LE ",    "exponentiation" },
  195. { CM_PCTCH,    "\\GD%"," 2RR  1LE ",    "delta %" },
  196. { CM_SUMADD,    "\\GS+"," 2RR  2LDS",    "summation plus" },
  197. { CM_SUMSUB,    "\\GS-"," 2RR  2LDS",    "summation minus" },
  198. { CM_SUMGET,    "\\GSREG?"," 0    1 E ","get summation register" },
  199. { CM_SUMSET,    "\\GSREG","R1B   0 ER",    "set summation register" },
  200. { CM_PWR,    "^",    " 2RR  1LE ",    "exponentiation" },
  201. { CM_SUMADD,    "~+",    " 2RR  2LDS",    "summation plus" },
  202. { CM_SUMSUB,    "~-",    " 2RR  2LDS",    "summation minus" },
  203. { CM_SUMGET,    "~REG?"," 0    1 E ",    "get summation register" },
  204. { CM_SUMSET,    "~REG",    "R1B   0 ER",    "set summation register" } };
  205.  
  206.     /* ---------- flags ---------- */
  207.  
  208. /* The flag array (part of memory) assumes 16 flags/int.  That way,
  209. the indices in this table don't have to be recomputed for different
  210. word sizes. */
  211.  
  212. enum FLGS { FL_AUTO, FL_PRTDBL, FL_PRTLWR, FL_CRDOVER, FL_ILPRT,
  213. FL_RECINC, FL_INTENA, FL_PRTENA, FL_NUMINP, FL_ALPINP, FL_IGNRANGE,
  214. FL_IGNERROR, FL_AUDIO, FL_USER, FL_RADIX, FL_DIGGRP, FL_CATALOG,
  215. FL_DMYDATE, FL_MANIO, FL_ABSMAN, FL_AUTOADD, FL_AUTOST, FL_DIGITS,
  216. FL_DISPFMT, FL_TRIGMODE, FL_CONTON, FL_SYSDATA, FL_PARTIAL, FL_SHIFT,
  217. FL_ALPHA, FL_LOWBAT, FL_SST, FL_PRGM, FL_IOREQ, FL_PSE, FL_MSG,
  218. FL_PRTEX, FL_WSIZE, FL_BINMODE, FL_CMPMODE, FL_CALMODE, FL_SUMBASE,
  219. FL_UPPREQ, FL_NOLNUMS, FL_LIMALPHA, FL_LIMFNAME, FL_LAST };
  220.  
  221.  
  222. struct flag {
  223.     enum FLGS flg;        /* flag id */
  224.     int start;        /* starting flag # */
  225.     int bits;        /* number of bits */
  226.     int index;        /* flag array index */
  227.     int shift;        /* flag array element shift */
  228.     int mask;        /* flag array element mask */
  229.     char *desc;        /* description */
  230.     };
  231.  
  232. #define NUMFLAGS    7    /* number of ints used to hold flags */
  233. #define MAXFLAG        100    /* largest flag supported */
  234.  
  235. struct flag flags[] = {        /* must be in enum FLGS order */
  236.     /* user flags */
  237. { FL_AUTO,    11, 1, 0, 11, 0x1, "auto execution (NS)" },
  238. { FL_PRTDBL,    12, 1, 0, 12, 0x1, "print double wide (NS)" },
  239. { FL_PRTLWR,    13, 1, 0, 13, 0x1, "print lower case" },
  240. { FL_CRDOVER,    14, 1, 0, 14, 0x1, "card reader allow overwrite (NS)" },
  241. { FL_ILPRT,    15, 2, 0, 15, 0x3, 
  242.     "HPIL printer: 0)manual 1)normal 2)trace 3)trace w/stack print" },
  243. { FL_RECINC,    17, 1, 1,  1, 0x1, "record incomplete" },
  244. { FL_INTENA,    18, 1, 1,  2, 0x1, "IL interrupt enable (NS)" },
  245. { FL_PRTENA,    21, 1, 1,  5, 0x1, "printer enabled" },
  246. { FL_NUMINP,    22, 1, 1,  6, 0x1, "numeric input available" },
  247. { FL_ALPINP,    23, 1, 1,  7, 0x1, "alpha input available" },
  248. { FL_IGNRANGE,    24, 1, 1,  8, 0x1, "ignore range errors (NS)" },
  249. { FL_IGNERROR,    25, 1, 1,  9, 0x1, "ignore any errors & clear" },
  250. { FL_AUDIO,    26, 1, 1, 10, 0x1, "audio I/O is ignored" },
  251. { FL_USER,    27, 1, 1, 11, 0x1, "user mode is active (NS)" },
  252. { FL_RADIX,    28, 1, 1, 12, 0x1, "radix mark: 0). 1)," },
  253. { FL_DIGGRP,    29, 1, 1, 13, 0x1, "digit groupings shown: 0)no 1)yes" },
  254. { FL_CATALOG,    30, 1, 1, 14, 0x1, "catalog set (NS)" },
  255. { FL_DMYDATE,    31, 1, 1, 15, 0x1, "date mode: 0)M.DY 1)D.MY" },
  256.     /* system flags */
  257. { FL_MANIO,    32, 1, 2,  0, 0x1, "IL man I/O mode (NS)" },
  258. { FL_ABSMAN,    33, 1, 2,  1, 0x1, "can control IL (NS)" },
  259. { FL_AUTOADD,    34, 1, 2,  2, 0x1, "prevent IL auto address (NS)" },
  260. { FL_AUTOST,    35, 1, 2,  3, 0x1, "disable auto start (NS)" },
  261. { FL_DIGITS,    36, 4, 2,  4, 0xF, "number of digits, 0-15" },
  262. { FL_DISPFMT,    40, 2, 2,  8, 0x3, 
  263.     "display format: 0)sci 1)eng 2)fix 3)std (41:really fix/eng mode)" },
  264. #define FLV_SCI        0x00
  265. #define FLV_ENG        0x01
  266. #define FLV_FIX        0x02
  267. #define FLV_STD        0x03
  268. { FL_TRIGMODE,    42, 2, 2, 10, 0x3,
  269.     "angle mode: 0)deg 1)rad 2)grad 3)rad (don't use)" },
  270. #define FLV_DEG        0x00
  271. #define FLV_RAD        0x01
  272. #define FLV_GRD        0x02
  273. #define FLV_RAD2    0x03
  274. { FL_CONTON,    44, 1, 2, 12, 0x1, "continuous on (NS)" },
  275. { FL_SYSDATA,    45, 1, 2, 13, 0x1, "system data entry" },
  276. { FL_PARTIAL,    46, 1, 2, 14, 0x1, "partial key sequence (NS)" },
  277. { FL_SHIFT,    47, 1, 2, 15, 0x1, "shift key pressed (NS)" },
  278. { FL_ALPHA,    48, 1, 3,  0, 0x1, "alpha keyboard active (NS)" },
  279. { FL_LOWBAT,    49, 1, 3,  1, 0x1, "low battery (NS)" },
  280. { FL_MSG,    50, 1, 3,  2, 0x1, "set when a message is displayed (NS)" },
  281. { FL_SST,    51, 1, 3,  3, 0x1, "single step mode (NS)" },
  282. { FL_PRGM,    52, 1, 3,  4, 0x1, "program mode (NS)" },
  283. { FL_IOREQ,    53, 1, 3,  5, 0x1, "IL I/O request (NS)" },
  284. { FL_PSE,    54, 1, 3,  6, 0x1, "set during pause (NS)" },
  285. { FL_PRTEX,    55, 1, 3,  7, 0x1, "printer exists" },
  286.     /* Freyja-local flags */
  287. { FL_WSIZE,    65, 8, 4,  0,0xFF, "binary integer word size" },
  288. { FL_BINMODE,    73, 2, 4,  8, 0x3, "binary numbers 0)dec 1)oct 2)bin 3)hex" },
  289. #define FLV_DEC        0x00
  290. #define FLV_OCT        0x01
  291. #define FLV_BIN        0x02
  292. #define FLV_HEX        0x03
  293. { FL_CMPMODE,    75, 2, 4, 10, 0x3,
  294.     "complement mode: 0)uns 1)1's 2)2's 3)uns (don't use)" },
  295. #define FLV_UNS        0x00
  296. #define FLV_1S        0x01
  297. #define FLV_2S        0x02
  298. #define FLV_UNS2    0x03
  299. { FL_CALMODE,    77, 2, 4, 12, 0x3,
  300.     "calendar mode: 0)360 1)actual 2)365 3)actual (don't use)" },
  301. #define FLV_360        0x00
  302. #define FLV_ACT        0x01
  303. #define FLV_365        0x02
  304. #define FLV_ACT2    0x03
  305. { FL_SUMBASE,    81,16,  5,  0,0xFFFF, "summation base register" },
  306. { FL_UPPREQ,    97, 1,  6,  0, 0x1, "commands must be upper case" },
  307. { FL_NOLNUMS,    98, 1,  6,  1, 0x1, "no line numbers are present" },
  308. { FL_LIMALPHA,    99, 1,  6,  2, 0x1, "alpha register limited to 24 chars" },
  309. { FL_LIMFNAME, 100, 1,  6,  3, 0x1, "file names limited to 7 characters" } };
  310.  
  311.     /* ---------- number format ---------- */
  312. struct number {
  313.     union    {
  314.         int b;        /* binary integer goes here */
  315.         double r;    /* real number goes here */
  316.         } n;
  317.     char type;        /* 'B' binary, 'R' real */
  318.     };
  319.  
  320.     /* ---------- memory ---------- */
  321.  
  322. #define NUMSTACK    5
  323. #define NUMREGS        (REGCOUNT + NUMSTACK)
  324. #define X        (NUMREGS)
  325. #define Y        (NUMREGS + 1)
  326. #define Z        (NUMREGS + 2)
  327. #define T        (NUMREGS + 3)
  328. #define L        (NUMREGS + 4)
  329.  
  330. #define NUMSUM        6
  331. #define SUMX        0
  332. #define SUMX2        1
  333. #define SUMY        2
  334. #define SUMY2        3
  335. #define SUMXY        4
  336. #define SUMN        5
  337.  
  338. static struct memory {
  339.     struct number r[NUMREGS + NUMSTACK];
  340.     int flags[NUMFLAGS];    /* the flags */
  341.     FLAG trace_mode;    /* is tracing on? */
  342.     FLAG stack_lift;
  343.     };
  344.  
  345.     /* ---------- constants ---------- */
  346.  
  347. #define PI    3.1415926535
  348.  
  349.     /* ---------- variables ---------- */
  350.  
  351. static struct memory m;            /* memory */
  352. static char fname[FNAMEMAX] = { NUL };    /* memory filename */
  353. static char input[WORKSIZE + 1];    /* buffer for holding input */
  354. static char fmt_buf[BINSIZE + 2];    /* buffer for U_Fmt */
  355. static int bin_mask;            /* word mask for binary operations */
  356. static char exit = NUL;            /* do we exit? NUL = no, N = yes,
  357.                     don't insert #, Y = yes, insert # */
  358. static enum CMDS pushedcmd = CM_NULL;    /* pushed command: execute first */
  359. static struct command *cmdptr;        /* current command */
  360. static int cmdnum;            /* numeric argument for command */
  361. static FLAG cmdind;            /* was it an indirect? */
  362. static struct number *cmdreg;        /* register pointer */
  363. static enum CMDS cmdcmd;        /* command for sto/rcl */
  364. static char *cmdrest;            /* rest of command string */
  365.  
  366.     /* Arguments for commands.  Values have been coerced. */
  367. static struct number x;
  368. static struct number y;
  369. static struct number z;
  370. static struct number t;
  371.  
  372. void U_Cmd();            /* void */
  373. void U_CmdSetup();        /* char arg, struct number *from,
  374.                 struct number *to */
  375. char *U_Dispatch();        /* enum CMDS cmd */
  376. struct command *U_FindCmd();    /* enum CMDS cmd */
  377. int U_FlGet();            /* enum FLGS f */
  378. void U_FlSet();            /* enum FLGS f, int value */
  379. char *U_Fmt();            /* struct number *nptr */
  380. char *U_FmtBin();        /* char *buf, int value, FLAG first */
  381. void U_FromTrig();        /* struct number *nptr */
  382. double U_HMSAdd();        /* double hms1, double hms2 */
  383. FLAG U_In();            /* void */
  384. void U_Load();            /* void */
  385. void U_Save();            /* void */
  386. void U_Status();        /* void */
  387. void U_ToBin();            /* struct number *nptr */
  388. double U_ToDate();        /* struct tm *tptr */
  389. double U_ToHMS();        /* double hr */
  390. double U_ToHR();        /* double hms */
  391. void U_ToReal();        /* struct number *nptr */
  392. void U_ToTM();            /* struct tm *tptr, double date */
  393. void U_ToTrig();        /* struct number *nptr */
  394. void U_Trace1();        /* void */
  395. void U_Trace2();        /* char *retval */
  396. void U_View();            /* void */
  397. void U_ViewSum();        /* void */
  398.  
  399. /* ------------------------------------------------------------ */
  400.  
  401. /* Initialize to default values. */
  402.  
  403. void
  404. UInit()
  405.     {
  406.     int cnt;
  407.  
  408.     for (cnt = 0; cnt < NUMREGS; cnt++) {
  409.         m.r[cnt].type = 'R';
  410.         m.r[cnt].n.r = 0.0;
  411.         }
  412.     for (cnt = 0; cnt < NUMFLAGS; cnt++) {
  413.         m.flags[cnt] = 0;
  414.         }
  415.     U_FlSet(FL_RADIX, 1);
  416.     U_FlSet(FL_DIGGRP, 1);
  417.     U_FlSet(FL_DIGITS, 4);
  418.     U_FlSet(FL_DISPFMT, FLV_STD);
  419.     U_FlSet(FL_WSIZE, BINSIZE);
  420.     bin_mask = ~0;
  421.     U_FlSet(FL_BINMODE, FLV_HEX);
  422.     U_FlSet(FL_CALMODE, FLV_ACT);
  423.     U_FlSet(FL_SUMBASE, 11);
  424.     m.trace_mode = FALSE;
  425.     m.stack_lift = TRUE;
  426.     }
  427.  
  428.  
  429. /* ------------------------------------------------------------ */
  430.  
  431. /* Calculator */
  432.  
  433. void
  434. UCalc()
  435.     {
  436.     uarg = 0;
  437.  
  438.     for (exit = NUL; exit == NUL; ) {
  439.         U_In();
  440.         if (cmdptr != NULL) U_Cmd();
  441.         }
  442.     if (exit == 'Y') BInsStr(U_Fmt(&m.r[X]));
  443.     DModeLine();
  444.     }
  445.  
  446.  
  447. /* ------------------------------------------------------------ */
  448.  
  449. /* Return the operation's description. */
  450.  
  451. char *
  452. UDescr(op)
  453.     int op;
  454.     {
  455.     return(commands[op].name);
  456.     }
  457.  
  458.  
  459. /* ------------------------------------------------------------ */
  460.  
  461. /* Enter the current number into the calculator. */
  462.  
  463. void
  464. UEnter()
  465.     {
  466.     char buf[WORKSIZE + 1];
  467.     FLAG isafter;
  468.     FLAG isfirst = TRUE;
  469.     char *cptr = buf;
  470.     int chr;
  471.  
  472.     WNumMark();
  473.     if (isafter = BIsAfterMark(mark)) BMarkSwap(mark);
  474.     BMarkToPoint(cwin->point);
  475.     while (cptr < &buf[sizeof(buf) - 2] && BIsBeforeMark(mark)) {
  476.         chr = BGetCharAdv();
  477.         if (isfirst) {
  478.             if (chr == '-') *cptr++ = '0';
  479.             isfirst = FALSE;
  480.             }            
  481.         if (chr == '-') chr = '~';
  482.         *cptr++ = chr;
  483.         }
  484.     *cptr++ = SP;
  485.     BPointToMark(cwin->point);
  486.     if (isafter) BMarkSwap(mark);
  487.     uarg = 0;
  488.  
  489.     KFromStr(buf, cptr - buf);
  490.     UCalc();
  491.     }
  492.  
  493.  
  494. /* ------------------------------------------------------------ */
  495.  
  496. /* Return the operation's help text. */
  497.  
  498. char *
  499. UHelp(op)
  500.     int op;
  501.     {
  502.     return(commands[op].help);
  503.     }
  504.  
  505.  
  506. /* ------------------------------------------------------------ */
  507.  
  508. /* Load and save the keyboard macro buffer. */
  509.  
  510. void
  511. ULoadMac()
  512.     {
  513.     int cnt;
  514.     int *iptr = KMacPtr();
  515.  
  516.     if (isuarg) {    /* load */
  517.         BMarkToPoint(cwin->point);
  518.         BMoveToStart();
  519.         for (cnt = 0; cnt < MACROMAX - 1 && !BIsEnd(); cnt++) {
  520.             *(iptr + cnt) = BGetCharAdv();
  521.             }
  522.         *(iptr + cnt) = KEYNONE;
  523.         BPointToMark(cwin->point);
  524.         }
  525.     else    {    /* save into buffer */
  526.         iptr = KMacPtr();
  527.         for (cnt = 0; cnt < MACROMAX && *(iptr + cnt) != KEYNONE;
  528.              cnt++) {
  529.             BInsChar(*(iptr + cnt));
  530.             }
  531.         }
  532.     uarg = 0;
  533.     }
  534.  
  535.  
  536. /* ------------------------------------------------------------ */
  537.  
  538. /* Return the number of operators. */
  539.  
  540. int
  541. UNumOps()
  542.     {
  543.     return(NUMCMDS);
  544.     }
  545.  
  546.  
  547. /* ------------------------------------------------------------ */
  548.  
  549. /* Insert a copy of the X register. */
  550.  
  551. void
  552. UPrintX()
  553.     {
  554.     uarg = 0;
  555.  
  556.     if (isuarg) {
  557.         WNumMark();
  558.         RRegDelete();
  559.         }
  560.     BInsStr(U_Fmt(&m.r[X]));
  561.     }
  562.  
  563.  
  564. /* ------------------------------------------------------------ */
  565.  
  566. /* Initialize the ./, and digsep on/off flags */
  567.  
  568. void
  569. USetup(iscomma, issep)
  570.     FLAG iscomma;
  571.     FLAG issep;
  572.     {
  573.     U_FlSet(FL_RADIX, iscomma);
  574.     U_FlSet(FL_DIGGRP, issep);
  575.     }
  576.  
  577.  
  578. /* ------------------------------------------------------------ */
  579.  
  580. /* Execute the current command. */
  581.  
  582. void
  583. U_Cmd()
  584.     {
  585.     struct number tmp;
  586.     char *retval;
  587.     int amt;
  588.  
  589. /* set up args */
  590.  
  591.     U_CmdSetup(cmdptr->desc[2], &m.r[X], &x);
  592.     U_CmdSetup(cmdptr->desc[3], &m.r[Y], &y);
  593.     U_CmdSetup(cmdptr->desc[4], &m.r[Z], &z);
  594.     U_CmdSetup(cmdptr->desc[5], &m.r[T], &t);
  595.  
  596. /* handle indirect registers */
  597.  
  598.     if (cmdptr->desc[0] == 'R' || cmdptr->desc[0] == 'P') {
  599.         if (cmdind) {
  600.             tmp = *cmdreg;
  601.             U_ToBin(&tmp);
  602.             if (tmp.n.b < 0 || tmp.n.b >= REGCOUNT) {
  603.                 DError("Unknown Indirect Register");
  604.                 cmdptr = NULL;
  605.                 return;
  606.                 }
  607.             cmdreg = &m.r[tmp.n.b];
  608.             }
  609.         }
  610.  
  611. /* handle trace */
  612.  
  613.     if (m.trace_mode) U_Trace1();
  614.  
  615. /* execute */
  616.  
  617.     retval = U_Dispatch(cmdptr->cmd);
  618.     if (retval == NULL) {
  619.  
  620. /* lastx */
  621.  
  622.         if (cmdptr->desc[7] == 'L') m.r[L] = m.r[X];
  623.  
  624. /* drop stack */
  625.  
  626.         if (cmdptr->desc[1] == '0') {
  627.             }
  628.         else if (cmdptr->desc[1] == '1') {
  629.             m.r[X] = m.r[Y];
  630.             m.r[Y] = m.r[Z];
  631.             m.r[Z] = m.r[T];
  632.             }
  633.         else if (cmdptr->desc[1] == '2') {
  634.             m.r[X] = m.r[Z];
  635.             m.r[Y] = m.r[T];
  636.             m.r[Z] = m.r[T];
  637.             }
  638.         else    {
  639.             m.r[X] = m.r[T];
  640.             m.r[Y] = m.r[T];
  641.             m.r[Z] = m.r[T];
  642.             }
  643.  
  644. /* save results */
  645.  
  646.         amt = cmdptr->desc[6] - '0';
  647.  
  648. /* stack lift disabled and new operation lifts the stack */
  649.         if (!m.stack_lift && cmdptr->desc[1] < cmdptr->desc[6]) {
  650.             amt = cmdptr->desc[6] - cmdptr->desc[1] - 1;
  651.             if (amt == 0) m.r[X] = x;
  652.             }
  653.  
  654.         if (amt <= 0) {
  655.             }
  656.         else if (amt == 1) {
  657.             m.r[T] = m.r[Z];
  658.             m.r[Z] = m.r[Y];
  659.             m.r[Y] = m.r[X];
  660.             m.r[X] = x;
  661.             }
  662.         else if (amt == 2) {
  663.             m.r[T] = m.r[Y];
  664.             m.r[Z] = m.r[X];
  665.             m.r[Y] = y;
  666.             m.r[X] = x;
  667.             }
  668.         else if (amt == 3) {
  669.             m.r[T] = m.r[X];
  670.             m.r[Z] = z;
  671.             m.r[Y] = y;
  672.             m.r[X] = x;
  673.             }
  674.         else    {
  675.             m.r[T] = t;
  676.             m.r[Z] = z;
  677.             m.r[Y] = y;
  678.             m.r[X] = x;
  679.             }
  680.  
  681. /* stack lift */
  682.  
  683.         m.stack_lift = cmdptr->desc[8] == 'E';
  684.         }
  685.     else    DError(retval);
  686.  
  687. /* handle trace */
  688.  
  689.     if (m.trace_mode) U_Trace2(retval);
  690.     }
  691.  
  692.  
  693. /* ------------------------------------------------------------ */
  694.  
  695. /* Setup the register according to the argument type. */
  696.  
  697. void
  698. U_CmdSetup(arg, from, to)
  699.     char arg;
  700.     struct number *from;
  701.     struct number *to;
  702.     {
  703.     if (arg != SP) {
  704.         *to = *from;
  705.         if (arg == 'B') U_ToBin(to);
  706.         else if (arg == 'R') U_ToReal(to);
  707.         }
  708.     }
  709.  
  710.  
  711. /* ------------------------------------------------------------ */
  712.  
  713. /* The command dispatch table.  Return NULL on success or a pointer to
  714. an error message if a failure. */
  715.  
  716. char *
  717. U_Dispatch(cmd)
  718.     enum CMDS cmd;
  719.     {
  720.     struct tm t;
  721.     struct number tmp;
  722.     struct number tmp2;
  723.     struct number sn;
  724.     struct number sx;
  725.     struct number sx2;
  726.     struct number sy;
  727.     struct number sy2;
  728.     struct buffer *bptr;
  729.     int cnt;
  730.     int num;
  731.     long ltmp;
  732.     char buf[WORKSIZE];
  733.     FLAG wasneg;
  734.  
  735.     switch (cmd) {
  736.  
  737.     case CM_ABS:
  738.         x.n.r = fabs(x.n.r);
  739.         break;
  740.  
  741.     case CM_ACOS:
  742.         if (x.n.r < -1.0 || x.n.r > 1.0) return("acos <-1 or >1");
  743.         x.n.r = acos(x.n.r);
  744.         U_ToTrig(&x);
  745.         break;
  746.  
  747.     case CM_ADD:
  748.         if (x.type == 'B' && y.type == 'B') {
  749.             x.n.b += y.n.b;
  750.             x.n.b &= bin_mask;
  751.             }
  752.         else    {
  753.             U_ToReal(&x);
  754.             U_ToReal(&y);
  755.             x.type = 'R';
  756.             x.n.r += y.n.r;
  757.             }
  758.         break;
  759.  
  760.     case CM_AND:
  761.         x.n.b &= y.n.b;
  762.         x.n.b &= bin_mask;
  763.         break;
  764.  
  765.      case CM_ASIN:
  766.         if (x.n.r < -1.0 || x.n.r > 1.0) return("asin <-1 or >1");
  767.         x.n.r = asin(x.n.r);
  768.         U_ToTrig(&x);
  769.         break;
  770.  
  771.      case CM_ATAN:
  772.         x.n.r = atan(x.n.r);
  773.         U_ToTrig(&x);
  774.         break;
  775.  
  776.      case CM_B:
  777.         U_FlSet(FL_BINMODE, FLV_BIN);
  778.         break;
  779.  
  780.     case CM_CF:
  781.         if (cmdnum < 1 || cmdnum > MAXFLAG) return("illegal flag");
  782.         num = cmdnum - 1;
  783.         m.flags[num >> 4] &= ~(1 << (num & 0xF));
  784.         break;
  785.  
  786.      case CM_CLRG:
  787.         for (cnt = 0; cnt < REGCOUNT; cnt++) {
  788.             m.r[cnt].type = 'R';
  789.             m.r[cnt].n.r = 0.0;
  790.             }
  791.         break;
  792.  
  793.      case CM_CLST:
  794.         for (cnt = X; cnt < L; cnt++) {
  795.             m.r[cnt].type = 'R';
  796.             m.r[cnt].n.r = 0.0;
  797.             }
  798.         break;
  799.  
  800.      case CM_CLSUM:
  801.         num = U_FlGet(FL_SUMBASE);
  802.         for (cnt = num; cnt < num + NUMSUM; cnt++) {
  803.             m.r[cnt].type = 'R';
  804.             m.r[cnt].n.r = 0.0;
  805.             }
  806.         break;
  807.  
  808.      case CM_CLX:
  809.         m.r[X].type = 'R';
  810.         m.r[X].n.r = 0.0;
  811.         break;
  812.  
  813.     case CM_COS:
  814.         U_FromTrig(&x);
  815.         x.n.r = cos(x.n.r);
  816.         break;
  817.  
  818.      case CM_D:
  819.         U_FlSet(FL_BINMODE, FLV_DEC);
  820.         break;
  821.  
  822.     case CM_DATE:
  823.         DNow(&t);
  824.         x.n.r = U_ToDate(&t);
  825.         x.type = 'R';
  826.         break;
  827.  
  828.     case CM_DATEM:
  829.         num = U_FlGet(FL_CALMODE);
  830.         U_ToTM(&t, y.n.r);
  831.         ltmp = DToDayN(&t, num) - x.n.b;
  832.         DToDate(&t, ltmp, num);
  833.         x.n.r = U_ToDate(&t);
  834.         x.type = 'R';
  835.         break;
  836.  
  837.     case CM_DATEP:
  838.         num = U_FlGet(FL_CALMODE);
  839.         U_ToTM(&t, y.n.r);
  840.         ltmp = DToDayN(&t, num) + x.n.b;
  841.         DToDate(&t, ltmp, num);
  842.         x.n.r = U_ToDate(&t);
  843.         x.type = 'R';
  844.         break;
  845.  
  846.     case CM_DDAYS:
  847.         num = U_FlGet(FL_CALMODE);
  848.         U_ToTM(&t, x.n.r);
  849.         ltmp = DToDayN(&t, num);
  850.         U_ToTM(&t, y.n.r);
  851.         x.n.r = ltmp - DToDayN(&t, num);
  852.         break;
  853.  
  854.      case CM_DEC:
  855.         if (x.type == 'R' && x.n.r < 0.0) return("Negative");
  856.         U_ToBin(&x);
  857.         xsprintf(buf, "%o", x.n.b);
  858.         if (!SToN(buf, &x.n.b, 10)) return("Invalid Integer");
  859.         break;
  860.  
  861.     case CM_DEFAULT:
  862.         UInit();
  863.         break;
  864.  
  865.      case CM_DEG:
  866.         U_FlSet(FL_TRIGMODE, FLV_DEG);
  867.         break;
  868.  
  869.     case CM_DIGSEPOFF:
  870.         U_FlSet(FL_DIGGRP, 0);
  871.         break;
  872.  
  873.     case CM_DIGSEPON:
  874.         U_FlSet(FL_DIGGRP, 1);
  875.         break;
  876.  
  877.      case CM_DIV:
  878.         if (x.n.r == 0.0) return("Divide by Zero");
  879.         x.n.r = y.n.r / x.n.r;
  880.         break;
  881.  
  882.     case CM_DMY:
  883.         U_FlSet(FL_DMYDATE, 1);
  884.         break;
  885.  
  886.     case CM_DOW:
  887.         U_ToTM(&t, x.n.r);
  888.         x.n.r = DOW(DToDayN(&t, 1));
  889.         break;
  890.  
  891.      case CM_DTOR:
  892.         x.n.r *= PI / 180.0;
  893.         break;
  894.  
  895.      case CM_ENTER:
  896.         y = x;
  897.         m.stack_lift = TRUE;
  898.         break;
  899.  
  900.     case CM_EXP:
  901.         x.n.r = exp(x.n.r);
  902.         break;
  903.  
  904.      case CM_EXPM1:
  905.         x.n.r = exp(x.n.r) - 1;
  906.         break;
  907.  
  908.      case CM_FACT:
  909.         if (x.n.r < 0.0) return("Negative");
  910.         for (cnt = x.n.r, x.n.r = 1.0; cnt > 1; cnt--) {
  911.             x.n.r *= cnt;
  912.             }
  913.         break;
  914.  
  915.      case CM_FRC:
  916.         wasneg = x.n.r < 0;
  917.         x.n.r = fabs(x.n.r);
  918.         x.n.r -= floor(x.n.r);
  919.         if (wasneg) x.n.r = -x.n.r;
  920.         break;
  921.  
  922.      case CM_GRAD:
  923.         U_FlSet(FL_TRIGMODE, FLV_GRD);
  924.         break;
  925.  
  926.      case CM_H:
  927.         U_FlSet(FL_BINMODE, FLV_HEX);
  928.         break;
  929.  
  930.      case CM_HELP:
  931.         HHelp();
  932.         DIncrDisplay();
  933.         break;
  934.  
  935.     case CM_HMS:
  936.         x.n.r = U_ToHMS(x.n.r);
  937.         break;
  938.  
  939.     case CM_HMSM:
  940.         x.n.r = U_HMSAdd(y.n.r, -x.n.r);
  941.         break;
  942.  
  943.     case CM_HMSP:
  944.         x.n.r = U_HMSAdd(y.n.r, x.n.r);
  945.         break;
  946.  
  947.     case CM_HR:
  948.         x.n.r = U_ToHR(x.n.r);
  949.         break;
  950.  
  951.      case CM_INT:
  952.         wasneg = x.n.r < 0;
  953.         x.n.r = fabs(x.n.r);
  954.         x.n.r = floor(x.n.r);
  955.         if (wasneg) x.n.r = -x.n.r;
  956.         break;
  957.  
  958.     case CM_INV:
  959.         if (x.n.r == 0.0) return("Divide by Zero");
  960.         x.n.r = 1.0 / x.n.r;
  961.         break;
  962.  
  963.      case CM_LASTX:
  964.         x = m.r[L];
  965.         break;
  966.  
  967.      case CM_LN:
  968.         if (x.n.r <= 0.0) return("Negative");
  969.         x.n.r = log(x.n.r);
  970.         break;
  971.  
  972.      case CM_LNP1:
  973.         if (x.n.r + 1.0 <= 0.0) return("Negative");
  974.         x.n.r = log(x.n.r + 1.0);
  975.         break;
  976.  
  977.      case CM_LOG:
  978.         if (x.n.r <= 0.0) return("Negative");
  979.         x.n.r = log10(x.n.r);
  980.         break;
  981.  
  982.     case CM_MDY:
  983.         U_FlSet(FL_DMYDATE, 0);
  984.         break;
  985.  
  986.      case CM_MEAN:
  987.         num = U_FlGet(FL_SUMBASE);
  988.         U_ToReal(&m.r[num + SUMN]);
  989.         U_ToReal(&m.r[num + SUMX]);
  990.         U_ToReal(&m.r[num + SUMY]);
  991.         sn  = m.r[num + SUMN];
  992.         sx  = m.r[num + SUMX];
  993.         sy  = m.r[num + SUMY];
  994.         if (sn.n.r == 0.0) return("Zero Items");
  995.         x.type = 'R';
  996.         x.n.r = sx.n.r / sn.n.r;
  997.         y.type = 'R';
  998.         y.n.r = sy.n.r / sn.n.r;
  999.         break;
  1000.  
  1001.     case CM_MEMLOAD:
  1002.         U_Load();
  1003.         break;
  1004.  
  1005.     case CM_MEMSAVE:
  1006.         U_Save();
  1007.         break;
  1008.  
  1009.     case CM_MEMSUM:
  1010.         U_ViewSum();
  1011.         break;
  1012.  
  1013.     case CM_MEMVIEW:
  1014.         U_View();
  1015.         break;
  1016.  
  1017.      case CM_MOD:
  1018.         if (x.n.r == 0.0) return("Mod of Zero");
  1019.         x.n.r = y.n.r - x.n.r * floor(y.n.r / x.n.r);
  1020.         break;
  1021.  
  1022.      case CM_MUL:
  1023.         if (x.type == 'B' && y.type == 'B') {
  1024.             x.n.b *= y.n.b;
  1025.             x.n.b &= bin_mask;
  1026.             }
  1027.         else    {
  1028.             U_ToReal(&x);
  1029.             U_ToReal(&y);
  1030.             x.type = 'R';
  1031.             x.n.r *= y.n.r;
  1032.             }
  1033.         break;
  1034.  
  1035.     case CM_NEG:
  1036.         x.n.r = -x.n.r;
  1037.         break;
  1038.  
  1039.      case CM_NOT:
  1040.         x.n.b = ~x.n.b;
  1041.         x.n.b &= bin_mask;
  1042.         break;
  1043.  
  1044.      case CM_NULL:
  1045.         break;
  1046.  
  1047.     case CM_NUM:
  1048.         break;
  1049.  
  1050.      case CM_O:
  1051.         U_FlSet(FL_BINMODE, FLV_OCT);
  1052.         break;
  1053.  
  1054.      case CM_OCT:
  1055.         if (x.type == 'R' && x.n.r < 0.0) return("Negative");
  1056.         U_ToBin(&x);
  1057.         xsprintf(buf, "%d", x.n.b);
  1058.         if (!SToN(buf, &x.n.b, 8)) return("Non-integer");
  1059.         break;
  1060.  
  1061.      case CM_OR:
  1062.         x.n.b |= y.n.b;
  1063.         x.n.b &= bin_mask;
  1064.         break;
  1065.  
  1066.      case CM_PCT:
  1067.         x.n.r *= y.n.r / 100.0;
  1068.         break;
  1069.  
  1070.      case CM_PCTCH:
  1071.         if (y.n.r == 0.0) return("Percent of Zero");
  1072.         x.n.r = 100.0 * (x.n.r - y.n.r) / y.n.r;
  1073.         break;
  1074.  
  1075.     case CM_PCTTOT:
  1076.         if (y.n.r == 0.0) return("Percent of Zero");
  1077.         x.n.r = 100.0 * x.n.r / y.n.r;
  1078.         break;
  1079.  
  1080.      case CM_PI:
  1081.         x.type = 'R';
  1082.         x.n.r = PI;
  1083.         break;
  1084.  
  1085.      case CM_PTOR:
  1086.         tmp.n.r = y.n.r;
  1087.         U_FromTrig(&tmp);
  1088.         y.n.r = x.n.r * sin(tmp.n.r);
  1089.         x.n.r = x.n.r * cos(tmp.n.r);
  1090.         break;
  1091.  
  1092.      case CM_PWR:
  1093.         if (y.n.r < 0.0 || (y.n.r == 0.0 && x.n.r < 0.0))
  1094.             return("Negative");
  1095.         x.n.r = pow(y.n.r, x.n.r);
  1096.         break;
  1097.  
  1098.      case CM_RAD:
  1099.         U_FlSet(FL_TRIGMODE, FLV_RAD);
  1100.         break;
  1101.  
  1102.     case CM_RADIXC:
  1103.         U_FlSet(FL_RADIX, 0);
  1104.         break;
  1105.  
  1106.     case CM_RADIXD:
  1107.         U_FlSet(FL_RADIX, 1);
  1108.         break;
  1109.  
  1110.      case CM_RCL:
  1111.         if (cmdnum < 0) {
  1112.             for (cnt = 0; KIsKey() == 'N'; cnt++) {
  1113.                 xsprintf(buf, "   %d   ", cnt);
  1114.                 DEcho(buf);
  1115.                 }
  1116.             KGetChar();
  1117.             return(NULL);
  1118.             }
  1119.         y = x;
  1120.         x = *cmdreg;
  1121.         U_Dispatch(cmdcmd);
  1122.         break;
  1123.  
  1124.      case CM_RDN:
  1125.         tmp = m.r[X];
  1126.         m.r[X] = m.r[Y];
  1127.         m.r[Y] = m.r[Z];
  1128.         m.r[Z] = m.r[T];
  1129.         m.r[T] = tmp;
  1130.         break;
  1131.  
  1132.      case CM_RTOD:
  1133.         x.n.r *= 180.0 / PI;
  1134.         break;
  1135.  
  1136.     case CM_RTOP:
  1137.         tmp.n.r = y.n.r * y.n.r;
  1138.         y.n.r = atan2(y.n.r, x.n.r);
  1139.         U_ToTrig(&y);
  1140.         x.n.r = sqrt(x.n.r * x.n.r + tmp.n.r);
  1141.         break;
  1142.  
  1143.      case CM_RUP:
  1144.         tmp = m.r[X];
  1145.         m.r[X] = m.r[T];
  1146.         m.r[T] = m.r[Z];
  1147.         m.r[Z] = m.r[Y];
  1148.         m.r[Y] = tmp;
  1149.         break;
  1150.  
  1151.      case CM_SDEV:
  1152.         num = U_FlGet(FL_SUMBASE);
  1153.         U_ToReal(&m.r[num + SUMN]);
  1154.         U_ToReal(&m.r[num + SUMX]);
  1155.         U_ToReal(&m.r[num + SUMX2]);
  1156.         U_ToReal(&m.r[num + SUMY]);
  1157.         U_ToReal(&m.r[num + SUMY2]);
  1158.         sn  = m.r[num + SUMN];
  1159.         sx  = m.r[num + SUMX];
  1160.         sx2 = m.r[num + SUMX2];
  1161.         sy  = m.r[num + SUMY];
  1162.         sy2 = m.r[num + SUMY2];
  1163.         tmp.n.r = sn.n.r * (sn.n.r - 1.0);
  1164.         if (tmp.n.r == 0.0) return("Zero Items");
  1165.  
  1166.         tmp2.n.r = (sn.n.r * sx2.n.r - sx.n.r * sx.n.r) / tmp.n.r;
  1167.         if (tmp2.n.r <= 0.0) return("Negative");
  1168.         x.type = 'R';
  1169.         x.n.r = sqrt(tmp2.n.r);
  1170.  
  1171.         tmp2.n.r = (sn.n.r * sy2.n.r - sy.n.r * sy.n.r) / tmp.n.r;
  1172.         if (tmp2.n.r <= 0.0) return("Negative");
  1173.         y.type = 'R';
  1174.         y.n.r = sqrt(tmp2.n.r);
  1175.         break;
  1176.  
  1177.     case CM_SF:
  1178.         if (cmdnum < 1 || cmdnum > MAXFLAG) return("illegal flag");
  1179.         num = cmdnum - 1;
  1180.         m.flags[num >> 4] |= 1 << (num & 0xF);
  1181.         break;
  1182.  
  1183.      case CM_SIGN:
  1184.         if (x.n.r < 0) x.n.r = -1.0;
  1185.         if (x.n.r > 0) x.n.r =  1.0;
  1186.         break;
  1187.  
  1188.      case CM_SIN:
  1189.         U_FromTrig(&x);
  1190.         x.n.r = sin(x.n.r);
  1191.         break;
  1192.  
  1193.      case CM_SQ:
  1194.         x.n.r *= x.n.r;
  1195.         break;
  1196.  
  1197.      case CM_SQRT:
  1198.         if (x.n.r <= 0.0) return("Negative or Zero");
  1199.         x.n.r = sqrt(x.n.r);
  1200.         break;
  1201.  
  1202.     case CM_STD:
  1203.         U_FlSet(FL_DISPFMT, FLV_STD);
  1204.         break;
  1205.  
  1206.      case CM_STO:
  1207.         y = *cmdreg;
  1208.         U_Dispatch(cmdcmd);
  1209.         *cmdreg = x;
  1210.         break;
  1211.  
  1212.     case CM_SUB:
  1213.         if (x.type == 'B' && y.type == 'B') {
  1214.             x.n.b = y.n.b - x.n.b;
  1215.             x.n.b &= bin_mask;
  1216.             }
  1217.         else    {
  1218.             U_ToReal(&x);
  1219.             U_ToReal(&y);
  1220.             x.type = 'R';
  1221.             x.n.r = y.n.r - x.n.r;
  1222.             }
  1223.         break;
  1224.  
  1225.      case CM_SUMADD:
  1226.         num = U_FlGet(FL_SUMBASE);
  1227.         U_ToReal(&m.r[num + SUMN]);
  1228.         U_ToReal(&m.r[num + SUMX]);
  1229.         U_ToReal(&m.r[num + SUMX2]);
  1230.         U_ToReal(&m.r[num + SUMY]);
  1231.         U_ToReal(&m.r[num + SUMY2]);
  1232.         U_ToReal(&m.r[num + SUMXY]);
  1233.         m.r[num + SUMN].n.r  += 1;
  1234.         m.r[num + SUMX].n.r  += x.n.r;
  1235.         m.r[num + SUMX2].n.r += x.n.r * x.n.r;
  1236.         m.r[num + SUMY].n.r  += y.n.r;
  1237.         m.r[num + SUMY2].n.r += y.n.r * y.n.r;
  1238.         m.r[num + SUMXY].n.r += x.n.r * y.n.r;
  1239.         x.n.r = m.r[num + SUMN].n.r;
  1240.         break;
  1241.  
  1242.      case CM_SUMGET:
  1243.         x.type = 'R';
  1244.         x.n.r = U_FlGet(FL_SUMBASE);
  1245.         break;
  1246.  
  1247.      case CM_SUMSET:
  1248.         num = cmdreg - &m.r[0];
  1249.         if (num < 0 || num > REGCOUNT - NUMSUM)
  1250.             return("Out of Range");
  1251.         U_FlSet(FL_SUMBASE, num);
  1252.         break;
  1253.  
  1254.      case CM_SUMSUB:
  1255.         num = U_FlGet(FL_SUMBASE);
  1256.         U_ToReal(&m.r[num + SUMN]);
  1257.         U_ToReal(&m.r[num + SUMX]);
  1258.         U_ToReal(&m.r[num + SUMX2]);
  1259.         U_ToReal(&m.r[num + SUMY]);
  1260.         U_ToReal(&m.r[num + SUMY2]);
  1261.         U_ToReal(&m.r[num + SUMXY]);
  1262.         m.r[num + SUMN].n.r  -= 1;
  1263.         m.r[num + SUMX].n.r  -= x.n.r;
  1264.         m.r[num + SUMX2].n.r -= x.n.r * x.n.r;
  1265.         m.r[num + SUMY].n.r  -= y.n.r;
  1266.         m.r[num + SUMY2].n.r -= y.n.r * y.n.r;
  1267.         m.r[num + SUMXY].n.r -= x.n.r * y.n.r;
  1268.         x.n.r = m.r[num + SUMN].n.r;
  1269.         break;
  1270.  
  1271.      case CM_SWAP:
  1272.         tmp = y;
  1273.         y = x;
  1274.         x = tmp;
  1275.         break;
  1276.  
  1277.      case CM_SWAPR:
  1278.         tmp = x;
  1279.         x = *cmdreg;
  1280.         *cmdreg = tmp;
  1281.         break;
  1282.  
  1283.      case CM_TAN:
  1284.         U_FromTrig(&x);
  1285.         x.n.r = tan(x.n.r);
  1286.         break;
  1287.  
  1288.     case CM_TENX:
  1289.         x.n.r = pow(10.0, x.n.r);
  1290.         break;
  1291.  
  1292.     case CM_TIME:
  1293.         DNow(&t);
  1294.         xsprintf(buf, "%d.%02d%02d", t.tm_hour, t.tm_min, t.tm_sec);
  1295.         sscanf(buf, "%lf", &x.n.r);
  1296.         x.type = 'R';
  1297.         break;
  1298.  
  1299.     case CM_TRACEOFF:
  1300.         m.trace_mode = FALSE;
  1301.         break;
  1302.  
  1303.     case CM_TRACEON:
  1304.         m.trace_mode = TRUE;
  1305.         break;
  1306.  
  1307.      case CM_WSIZE:
  1308.         if (x.n.b < 0 || x.n.b > BINSIZE) return("Out of Range");
  1309.         U_FlSet(FL_WSIZE, (int)x.n.b);
  1310.         if (x.n.b == BINSIZE)
  1311.             bin_mask = ~0;
  1312.         else    bin_mask = (1 << x.n.b) - 1;
  1313.         break;
  1314.  
  1315.      case CM_WSIZEQ:
  1316.         x.type = 'B';
  1317.         x.n.b = U_FlGet(FL_WSIZE);
  1318.         break;
  1319.  
  1320.     case CM_X360:
  1321.         U_FlSet(FL_CALMODE, FLV_360);
  1322.         break;
  1323.  
  1324.     case CM_X365:
  1325.         U_FlSet(FL_CALMODE, FLV_365);
  1326.         break;
  1327.  
  1328.     case CM_XACTUAL:
  1329.         U_FlSet(FL_CALMODE, FLV_ACT);
  1330.         break;
  1331.  
  1332.      case CM_XCAL:
  1333.         U_ToTM(&t, x.n.r);
  1334.         DXCal(&t);
  1335.         DIncrDisplay();
  1336.         break;
  1337.  
  1338.      case CM_XCALD:
  1339.         DMove(x.n.b);
  1340.         DIncrDisplay();
  1341.         break;
  1342.  
  1343.     case CM_XEQ:
  1344.         bptr = BBufFind(cmdrest);
  1345.         if (bptr == NULL) return("unknown program");
  1346.         KFromBuf(bptr);
  1347.         break;
  1348.  
  1349.      case CM_XOR:
  1350.         x.n.b ^= y.n.b;
  1351.         x.n.b &= bin_mask;
  1352.         break;
  1353.  
  1354.      case CM_XRND:
  1355.         num = x.n.b;
  1356.         for (cnt = 0; cnt < num; cnt++) y.n.r *= 10.0;
  1357.         y.n.r += (y.n.r > 0) ? 0.5 : -0.5;
  1358.         tmp.n.b = y.n.r;
  1359.         x.n.r = tmp.n.b;
  1360.         for (cnt = 0; cnt < num; cnt++) x.n.r /= 10.0;
  1361.         x.type = 'R';
  1362.         break;
  1363.  
  1364.      case CM_XROOT:
  1365.         if (y.n.r < 0.0 || (y.n.r == 0.0 && x.n.r <= 0.0))
  1366.             return("Negative");
  1367.         x.n.r = pow(y.n.r, 1.0 / x.n.r);
  1368.         break;
  1369.         }
  1370.     return(NULL);
  1371.     }
  1372.  
  1373.  
  1374. /* ------------------------------------------------------------ */
  1375.  
  1376. /* Return a pointer to the command structure for the specified
  1377. command. */
  1378.  
  1379. struct command *
  1380. U_FindCmd(cmd)
  1381.     enum CMDS cmd;
  1382.     {
  1383.     struct command *cptr;
  1384.  
  1385.     for (cptr = commands; cptr < &commands[NUMCMDS]; cptr++) {
  1386.         if (cmd == cptr->cmd) return(cptr);
  1387.         }
  1388.     return(NULL);
  1389.     }
  1390.  
  1391.  
  1392. /* ------------------------------------------------------------ */
  1393.  
  1394. /* Return the value of the specified flag. */
  1395.  
  1396. int
  1397. U_FlGet(f)
  1398.     enum FLGS f;
  1399.     {
  1400.     struct flag *fptr = &flags[(int)f];
  1401.  
  1402.     return((m.flags[fptr->index] >> fptr->shift) & fptr->mask);
  1403.     }
  1404.  
  1405.  
  1406. /* ------------------------------------------------------------ */
  1407.  
  1408. /* Set the specified flag to the supplied value. */
  1409.  
  1410. void
  1411. U_FlSet(f, v)
  1412.     enum FLGS f;
  1413.     int v;
  1414.     {
  1415.     struct flag *fptr = &flags[(int)f];
  1416.  
  1417.     v = (v & fptr->mask) << fptr->shift;
  1418.     m.flags[fptr->index] &= ~(fptr->mask << fptr->shift);
  1419.     m.flags[fptr->index] |= v;
  1420.     }
  1421.  
  1422.  
  1423. /* ------------------------------------------------------------ */
  1424.  
  1425. /* Return a pointer to a static buffer that contains a formatted
  1426. version of the number. */
  1427.  
  1428. char *
  1429. U_Fmt(nptr)
  1430.     struct number *nptr;
  1431.     {
  1432.     int mode = U_FlGet(FL_BINMODE);
  1433.     int cnt;
  1434.     FLAG iscomma = U_FlGet(FL_RADIX) == 0;
  1435.     char *cptr;
  1436.     char *cptr2;
  1437.  
  1438.     if (nptr->type == 'B') {
  1439.         switch (mode) {
  1440.  
  1441.         case FLV_BIN:
  1442.             *fmt_buf = '#';
  1443.             U_FmtBin(&fmt_buf[1], nptr->n.b, TRUE);
  1444.             strcat(fmt_buf, "b");
  1445.             break;
  1446.  
  1447.         case FLV_OCT:
  1448.             xsprintf(fmt_buf, "#%oo", nptr->n.b);
  1449.             break;
  1450.  
  1451.         case FLV_DEC:
  1452.             xsprintf(fmt_buf, "#%ud", nptr->n.b);
  1453.             break;
  1454.  
  1455.         case FLV_HEX:
  1456.             xsprintf(fmt_buf, "#%xh", nptr->n.b);
  1457.             break;
  1458.             }
  1459.         }
  1460.     else    {
  1461.         sprintf(fmt_buf, "%.9lg", nptr->n.r);
  1462.             /* handle comma */
  1463.         if (iscomma) {
  1464.             for (cptr = fmt_buf; *cptr != NUL; cptr++) {
  1465.                 if (*cptr == '.') *cptr = ',';
  1466.                 }
  1467.             }
  1468.             /* handle digit separator */
  1469.         if (U_FlGet(FL_DIGGRP) == 1) {
  1470.             cptr2 = fmt_buf;
  1471.             if (*cptr2 == '-') cptr2++;
  1472.  
  1473.             cnt = 0;
  1474.             for (cptr = cptr2; xisdigit(*cptr); cptr++, cnt++) ;
  1475.             while (cnt > 3) {
  1476.                 cptr -= 3;
  1477.                 memmove(cptr + 1, cptr, strlen(cptr) + 1);
  1478.                 *cptr = iscomma ? '.' : ',';
  1479.                 cnt -= 3;
  1480.                 }
  1481.             }
  1482.         }
  1483.     return(fmt_buf);
  1484.     }
  1485.  
  1486.  
  1487. /* ------------------------------------------------------------ */
  1488.  
  1489. /* Print out a binary integer. */
  1490.  
  1491. char *
  1492. U_FmtBin(buf, value, first)
  1493.     char *buf;
  1494.     int value;
  1495.     FLAG first;
  1496.     {
  1497.     if (value >= 2) buf = U_FmtBin(buf, value / 2, FALSE);
  1498.     if (value == 0 && first)
  1499.         *buf++ = '0';
  1500.     else    *buf++ = (value % 2) + '0';
  1501.     *buf = NUL;
  1502.     return(buf);
  1503.     }
  1504.  
  1505.  
  1506. /* ------------------------------------------------------------ */
  1507.  
  1508. /* Convert the number in the current trig mode to radians. */
  1509.  
  1510. void
  1511. U_FromTrig(nptr)
  1512.     struct number *nptr;
  1513.     {
  1514.     int mode = U_FlGet(FL_TRIGMODE);
  1515.  
  1516.     if (mode == FLV_DEG) nptr->n.r *= PI / 180.00;
  1517.     else if (mode == FLV_GRD) nptr->n.r *= PI / 200.00;
  1518.     }
  1519.  
  1520.  
  1521. /* ------------------------------------------------------------ */
  1522.  
  1523. /* Add the two times in hms format. */
  1524.  
  1525. double
  1526. U_HMSAdd(hms1, hms2)
  1527.     double hms1;
  1528.     double hms2;
  1529.     {
  1530.     double hr1;
  1531.     double hr2;
  1532.  
  1533.     hr1 = U_ToHR(hms1);
  1534.     hr2 = U_ToHR(hms2);
  1535.     return(U_ToHMS(hr1 + hr2));
  1536.     }
  1537.  
  1538.  
  1539. /* ------------------------------------------------------------ */
  1540.  
  1541. /* Input the next command. */
  1542.  
  1543. FLAG
  1544. U_In()
  1545.     {
  1546.     int chr;
  1547.     int amt;
  1548.     int cnt;
  1549.     int base;
  1550.     char buf[BIGBUFFSIZE];
  1551.     char *cptr;
  1552.     char *cptr2;
  1553.     FLAG isdone = FALSE;
  1554.     FLAG iscomma;
  1555.  
  1556.     cmdptr = NULL;
  1557.     *input = NUL;
  1558.     if (pushedcmd != CM_NULL) {
  1559.         cmdptr = U_FindCmd(pushedcmd);
  1560.         pushedcmd = CM_NULL;
  1561.         return;
  1562.         }
  1563.     while (!isdone) {
  1564.         U_Status();
  1565.  
  1566.         amt = strlen(input);
  1567.         chr = KGetChar();
  1568. #if defined(MSDOS)
  1569.         if (chr >= 256) {    /* function key */
  1570.             chr -= 256;
  1571.             if (c.g.special == 'J' && chr >= 133 && chr <= 141) {
  1572.                 TabDispatch(chr + 256, 0);
  1573.                 if (doabort) exit = 'N';
  1574.                 return;
  1575.                 }
  1576.             switch (chr) {
  1577.  
  1578.             case 59:    /* F1 */
  1579.                 pushedcmd = CM_HELP;
  1580.                 isdone = TRUE;
  1581.                 break;
  1582.  
  1583.             case 67:    /* F9 */
  1584.             case 38:    /* Alt-L */
  1585.                 chr = '-';
  1586.                 goto chs;
  1587.                 /*break;*/
  1588.  
  1589.             case 93:    /* Shift-F10 */
  1590.                 exit = 'N';
  1591.                 MExit();
  1592.                 return;
  1593.                 /*break;*/
  1594.  
  1595.             case 48:    /* Alt-B */
  1596.                 pushedcmd = CM_LASTX;
  1597.                 isdone = TRUE;
  1598.                 break;
  1599.  
  1600.             case 46:    /* Alt-C */
  1601.                 pushedcmd = CM_SWAP;
  1602.                 isdone = TRUE;
  1603.                 break;
  1604.  
  1605.             case 50:    /* Alt-M */
  1606.                 xstrcpy(input, "RCL");
  1607.                 amt = strlen(input);
  1608.                 break;
  1609.  
  1610.             case 49:    /* Alt-N */
  1611.                 xstrcpy(input, "STO");
  1612.                 amt = strlen(input);
  1613.                 break;
  1614.  
  1615.             case 47:    /* Alt-V */
  1616.                 pushedcmd = CM_RDN;
  1617.                 isdone = TRUE;
  1618.                 break;
  1619.  
  1620.             case 45:    /* Alt-X */
  1621.                 pushedcmd = CM_INV;
  1622.                 isdone = TRUE;
  1623.                 break;
  1624.  
  1625.             case 44:    /* Alt-Z */
  1626.                 pushedcmd = CM_SQRT;
  1627.                 isdone = TRUE;
  1628.                 break;
  1629.  
  1630.             default:
  1631.                 TBell();
  1632.                 return;
  1633.                 /*break;*/
  1634.                 }
  1635.             continue;
  1636.             }
  1637. #endif
  1638.  
  1639.         if (!isdone) {
  1640.             switch (chr) {
  1641.  
  1642.             case KEYQUIT:
  1643.             case KEYABORT:
  1644.             case ESC:
  1645.             case BEL:
  1646.             case '$':
  1647.                 exit = 'N';
  1648.                 isdone = TRUE;
  1649.                 break;
  1650.  
  1651.             case LF:
  1652.                 exit = 'Y';
  1653.                 isdone = TRUE;
  1654.                 break;
  1655.  
  1656.             case BS:
  1657.             case DEL:
  1658.                 if (*input != NUL) input[amt - 1] = NUL;
  1659.                 else    {
  1660.                     cmdptr = U_FindCmd(CM_CLX);
  1661.                     isdone = TRUE;
  1662.                     }
  1663.                 break;
  1664.  
  1665.             case SP:
  1666.             case CR:
  1667.                 isdone = TRUE;
  1668.                 break;
  1669.  
  1670.             case '%':
  1671.                 if (*input == '\'') goto accumulate;
  1672.                 pushedcmd = CM_PCT;
  1673.                 isdone = TRUE;
  1674.                 break;
  1675.  
  1676.             case '*':
  1677.                 if (*input == '\'') goto accumulate;
  1678.                 pushedcmd = CM_MUL;
  1679.                 isdone = TRUE;
  1680.                 break;
  1681.  
  1682.             case '+':
  1683.                 if (*input == '\'') goto accumulate;
  1684.                 pushedcmd = CM_ADD;
  1685.                 isdone = TRUE;
  1686.                 break;
  1687.  
  1688.             case '-':
  1689.                 if (*input == '\'') goto accumulate;
  1690.                 pushedcmd = CM_SUB;
  1691.                 isdone = TRUE;
  1692.                 break;
  1693.  
  1694.             case '/':
  1695.                 if (*input == '\'') goto accumulate;
  1696.                 pushedcmd = CM_DIV;
  1697.                 isdone = TRUE;
  1698.                 break;
  1699.  
  1700.             case '^':
  1701.                 if (*input == '\'') goto accumulate;
  1702.                 pushedcmd = CM_PWR;
  1703.                 isdone = TRUE;
  1704.                 break;
  1705.  
  1706.             case '\'':
  1707.                 if (*input == '\'') goto accumulate;
  1708.                 if (amt >= sizeof(input) - 1) {
  1709.                     input[amt - 1] = NUL;
  1710.                     TBell();
  1711.                     }
  1712.                 memmove(input + 1, input, amt + 1);
  1713.                 *input = '\'';
  1714.                 break;
  1715.  
  1716.             case '`':
  1717.             case '~':
  1718. chs:
  1719.                 if (*input == '\'') goto accumulate;
  1720.                 if (*input == NUL) {
  1721.                     cmdptr = U_FindCmd(CM_NEG);
  1722.                     isdone = TRUE;
  1723.                     }
  1724.                 else    {
  1725.                     cptr = input + amt;
  1726.                     while (cptr > input &&
  1727.                         xtoupper(*cptr) != 'E' &&
  1728.                         *cptr != '-') cptr--;
  1729.                     if (*cptr == '-') {
  1730.                         xstrcpy(cptr, cptr + 1);
  1731.                         }
  1732.                     else    {
  1733.                         if (amt >= sizeof(input) - 1) {
  1734.                             input[amt - 1] = NUL;
  1735.                             TBell();
  1736.                             }
  1737.                         if (xtoupper(*cptr) == 'E')
  1738.                             cptr++;
  1739.                         memmove(cptr + 1, cptr,
  1740.                             strlen(cptr) + 1);
  1741.                         *cptr = '-';
  1742.                         }
  1743.                     }
  1744.                 break;
  1745.  
  1746.             default:
  1747. accumulate:
  1748.                 if (amt >= sizeof(input) - 1) {
  1749.                     input[amt - 1] = NUL;
  1750.                     TBell();
  1751.                     }
  1752.  
  1753.                 input[amt] = chr;
  1754.                 input[amt + 1] = NUL;
  1755.                 break;
  1756.                 }
  1757.             }
  1758.         }
  1759.     if (*input == NUL || cmdptr != NULL) return;
  1760.     if (*input == '\'') xstrcpy(input, input + 1);
  1761.  
  1762. /* check for binary numbers */
  1763.  
  1764.     if (*input == '#') {
  1765.         cnt = U_FlGet(FL_BINMODE);
  1766.         if (cnt == FLV_BIN) base = 2;
  1767.         else if (cnt == FLV_OCT) base = 8;
  1768.         else if (cnt == FLV_DEC) base = 10;
  1769.         else base = 16;
  1770.         if (!SToN(&input[1], &x.n.b, base)) {
  1771.             DError("Invalid binary number");
  1772.             return;
  1773.             }
  1774.         x.n.b &= bin_mask;
  1775.         x.type = 'B';
  1776.         cmdptr = U_FindCmd(CM_NUM);
  1777.         return;
  1778.         }
  1779.  
  1780. /* try for real number */
  1781.  
  1782.     /* handle radix mark, dig sep char, ~->- */
  1783.     iscomma = U_FlGet(FL_RADIX) == 0;
  1784.     for (cptr = input, cptr2 = buf; *cptr != NUL; cptr++) {
  1785.         chr = *cptr;
  1786.         if (chr == '~' || chr == '`') chr = '-';
  1787.         else if (iscomma) {
  1788.             if (chr == ',') chr = '.';
  1789.             else if (chr == '.') continue;
  1790.             }
  1791.         else    {
  1792.             if (chr == ',') continue;
  1793.             }
  1794.         *cptr2++ = chr;
  1795.         }
  1796.     *cptr2 = NUL;
  1797.  
  1798.     /* handle numbers that start with EEX */
  1799.     cptr = buf;
  1800.     if (*cptr == '-') cptr++;
  1801.     if (xtoupper(*cptr) == 'E') {
  1802.         memmove(cptr + 1, cptr, strlen(cptr) + 1);
  1803.         *cptr = '1';
  1804.         }
  1805.  
  1806. /* check for real number */
  1807.     if (sscanf(buf, "%lf", &x.n.r) == 1) {
  1808.         x.type = 'R';
  1809.         cmdptr = U_FindCmd(CM_NUM);
  1810.         return;
  1811.         }
  1812.  
  1813. /* else command */
  1814.     if (U_FlGet(FL_UPPREQ)) {
  1815.         for (cmdptr = commands; cmdptr < &commands[NUMCMDS];
  1816.              cmdptr++) {
  1817.             if (cmdptr->desc[0] == SP) {
  1818.                 if (strcmp(input, cmdptr->name) == 0) break;
  1819.                 }
  1820.             else    {
  1821.                 if (strncmp(input, cmdptr->name,
  1822.                      strlen(cmdptr->name)) == 0) break;
  1823.                 }
  1824.             }
  1825.         }
  1826.     else    {
  1827.         for (cmdptr = commands; cmdptr < &commands[NUMCMDS];
  1828.              cmdptr++) {
  1829.             if (cmdptr->desc[0] == SP) {
  1830.                 if (strequ(input, cmdptr->name)) break;
  1831.                 }
  1832.             else    {
  1833.                 if (strnequ(input, cmdptr->name,
  1834.                     strlen(cmdptr->name))) break;
  1835.                 }
  1836.             }
  1837.         }
  1838.     if (cmdptr >= &commands[NUMCMDS]) {
  1839.         DError("Unknown Command");
  1840.         cmdptr = NULL;
  1841.         return;
  1842.         }
  1843.     if (cmdptr->desc[0] == SP) return;
  1844.  
  1845. /* process suffix */
  1846.  
  1847.     cptr = &input[strlen(cmdptr->name)];
  1848.     cmdrest = cptr;
  1849.     cmdcmd = CM_NULL;
  1850.     cmdind = FALSE;
  1851.     cmdnum = 0;
  1852.     cmdreg = &m.r[0];
  1853.  
  1854.     if (cmdptr->desc[0] == 'B') return;
  1855.  
  1856. /* is operator allowed? */
  1857.  
  1858.     if (cmdptr->desc[0] == 'P') {
  1859.         if (*cptr == '*')    { cmdcmd = CM_MUL; cptr++; }
  1860.         else if (*cptr == '+')    { cmdcmd = CM_ADD; cptr++; }
  1861.         else if (*cptr == '-')    { cmdcmd = CM_SUB; cptr++; }
  1862.         else if (*cptr == '/')    { cmdcmd = CM_DIV; cptr++; }
  1863.         else if (*cptr == '^')    { cmdcmd = CM_PWR; cptr++; }
  1864.         }
  1865.  
  1866. /* is indirect allowed? */
  1867.  
  1868.     if (cmdptr->desc[0] == 'R' || cmdptr->desc[0] == 'P') {
  1869.         if (*cptr == '.') {
  1870.             cmdind = TRUE;
  1871.             cptr++;
  1872.             }
  1873.         else if (U_FlGet(FL_UPPREQ) ?
  1874.              strncmp(cptr, "IND", 3) == 0 :
  1875.              strnequ(cptr, "IND", 3)) {
  1876.             cmdind = TRUE;
  1877.             cptr += 3;
  1878.             }
  1879.         /* check for register name */
  1880.  
  1881.         if (xisalpha(*cptr)) {
  1882.             if (*(cptr + 1) != NUL) {
  1883.                 DError("Unknown Register");
  1884.                 cmdptr = NULL;
  1885.                 return;
  1886.                 }
  1887.             if (!U_FlGet(FL_UPPREQ)) *cptr = xtoupper(*cptr);
  1888.             if (*cptr == 'X') { cmdreg = &m.r[X]; cmdnum = X; }
  1889.             else if (*cptr == 'Y') {cmdreg = &m.r[Y]; cmdnum = Y; }
  1890.             else if (*cptr == 'Z') {cmdreg = &m.r[Z]; cmdnum = Z; }
  1891.             else if (*cptr == 'T') {cmdreg = &m.r[T]; cmdnum = T; }
  1892.             else if (*cptr == 'L') {cmdreg = &m.r[L]; cmdnum = L; }
  1893.             else    {
  1894.                 DError("Unknown Register");
  1895.                 cmdptr = NULL;
  1896.                 return;
  1897.                 }
  1898.             return;
  1899.             }
  1900.         }
  1901.  
  1902. /* number is always allowed by the time that you get here */
  1903.  
  1904.     if (cmdptr->cmd == CM_RCL && *cptr == '~' || *cptr == '-') {
  1905.         cmdnum = -78;
  1906.         return;
  1907.         }
  1908.     if (!SToN(cptr, &cmdnum, 10)) {
  1909.         DError("Unknown Register");
  1910.         cmdptr = NULL;
  1911.         return;
  1912.         }
  1913.     if (cmdnum < 0 || cmdnum >= REGCOUNT) {
  1914.         DError("Unknown Register");
  1915.         cmdptr = NULL;
  1916.         return;
  1917.         }
  1918.     cmdreg = &m.r[cmdnum];
  1919.     }
  1920.  
  1921.  
  1922. /* ------------------------------------------------------------ */
  1923.  
  1924. /* Ask for a file name and load memory from that file. */
  1925.  
  1926. void
  1927. U_Load()
  1928.     {
  1929.     struct memory m2;
  1930.     int fd;
  1931.  
  1932.     if (KGetStr("Load memory from file", fname, sizeof(fname)) != 'Y') return;
  1933. #if defined(MSDOS)
  1934. #define O_RDONLY    0    /* dummy */
  1935. #endif
  1936.     if ((fd = open(fname, O_RDONLY, 0)) < 0) {
  1937.         DError("Cannot open file.");
  1938.         return;
  1939.         }
  1940.     if (read(fd, (char *)&m2, sizeof(m2)) != sizeof(m2))
  1941.         DError("Cannot read file.");
  1942.     else    m = m2;
  1943.     close(fd);
  1944.     }
  1945.  
  1946.  
  1947. /* ------------------------------------------------------------ */
  1948.  
  1949. /* Save the configuration information.  Print a message on error. */
  1950.  
  1951. void
  1952. U_Save()
  1953.     {
  1954.     int fd;
  1955.  
  1956.     if (KGetStr("Save memory to file", fname, sizeof(fname)) != 'Y') return;
  1957. #if defined(MSDOS)
  1958.     if ((fd = creat(cbuf->fname)) < 0) {
  1959. #endif
  1960. #if defined(UNIX)
  1961.     if ((fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
  1962. #endif
  1963.         DError("Cannot create file.");
  1964.         return;
  1965.         }
  1966.     if (write(fd, (char *)&m, sizeof(m)) != sizeof(m))
  1967.         DError("Cannot write file.");
  1968.     close(fd);
  1969.     }
  1970.  
  1971.  
  1972. /* ------------------------------------------------------------ */
  1973.  
  1974. /* Display the calculator status line */
  1975.  
  1976. void
  1977. U_Status()
  1978.     {
  1979.     char buf[4 * LINEBUFFSIZE];
  1980.     char *cptr = buf;
  1981.     int amt;
  1982.  
  1983.     if (KIsKey() == 'Y') return;
  1984.  
  1985.     xsprintf(cptr, "L)%s  ", U_Fmt(&m.r[L]));
  1986.     cptr += strlen(cptr);
  1987.     xsprintf(cptr, "T)%s  ", U_Fmt(&m.r[T]));
  1988.     cptr += strlen(cptr);
  1989.     xsprintf(cptr, "Z)%s  ", U_Fmt(&m.r[Z]));
  1990.     cptr += strlen(cptr);
  1991.     xsprintf(cptr, "Y)%s  ", U_Fmt(&m.r[Y]));
  1992.     cptr += strlen(cptr);
  1993.     xsprintf(cptr, "X)%s ", U_Fmt(&m.r[X]));
  1994.     cptr += strlen(cptr);
  1995.  
  1996.     if (TMaxCol() >= 80)
  1997.         amt = (TMaxCol() - WORKSIZE) - (cptr - buf);
  1998.     else    amt = (TMaxCol() - 12) - (cptr - buf);
  1999.     if (amt > 0) {
  2000.         while (amt-- > 0) *cptr++ = SP;
  2001.         *cptr = NUL;
  2002.         }
  2003.     else    {
  2004.         xstrcpy(buf, buf - amt);
  2005.         cptr = buf + strlen(buf);
  2006.         }
  2007.     *cptr++ = '>';
  2008.     *cptr = NUL;
  2009.     xstrcpy(cptr, input);
  2010.     DEcho(buf);
  2011.     TSetPoint(TMaxRow() - 1, strlen(buf));
  2012.     }
  2013.  
  2014.  
  2015. /* ------------------------------------------------------------ */
  2016.  
  2017. /* Convert the number to a binary number, if required. */
  2018.  
  2019. void
  2020. U_ToBin(nptr)
  2021.     struct number *nptr;
  2022.     {
  2023.     double r;
  2024.  
  2025.     if (nptr->type == 'R') {
  2026.         r = nptr->n.r;
  2027.         nptr->n.b = r;
  2028.         nptr->type = 'B';
  2029.         }
  2030.     }
  2031.  
  2032.  
  2033. /* ------------------------------------------------------------ */
  2034.  
  2035. /* Convert the date to a real number according to the current date
  2036. format. */
  2037.  
  2038. double
  2039. U_ToDate(tptr)
  2040.     struct tm *tptr;
  2041.     {
  2042.     double tmp;
  2043.     double i;
  2044.     double f;
  2045.  
  2046.     if (U_FlGet(FL_DMYDATE)) {
  2047.         i = tptr->tm_mday;
  2048.         f = tptr->tm_mon + 1;
  2049.         }
  2050.     else    {
  2051.         i = tptr->tm_mon + 1;
  2052.         f = tptr->tm_mday;
  2053.         }
  2054.     tmp = tptr->tm_year;
  2055.     tmp /= 1000000.;
  2056.     tmp += f / 100.;
  2057.     tmp += i;
  2058.     return(tmp);
  2059.     }
  2060.  
  2061.  
  2062. /* ------------------------------------------------------------ */
  2063.  
  2064. /* Convert a time in decimal hours form to HH.MMSSss. */
  2065.  
  2066. double
  2067. U_ToHMS(hr)
  2068.     double hr;
  2069.     {
  2070.     double tmp;
  2071.     FLAG isneg = FALSE;
  2072.     int h;
  2073.     int m;
  2074.     int s;
  2075.  
  2076.     if (hr < 0.0) {
  2077.         isneg = TRUE;
  2078.         hr = -hr;
  2079.         }
  2080.  
  2081.     h = hr;
  2082.  
  2083.     hr -= floor(hr);
  2084.     hr *= 60.;
  2085.     m = hr;
  2086.  
  2087.     hr -= floor(hr);
  2088.     hr *= 6000.;
  2089.     s = hr;
  2090. /* round hundreths of seconds off */
  2091.     s += 50;
  2092.     s /= 100;
  2093.  
  2094.     tmp = h;
  2095.     tmp += (double)m / 100.;
  2096.     tmp += (double)s / 10000.;
  2097.     if (isneg) tmp = -tmp;
  2098.     return(tmp);
  2099.     }
  2100.  
  2101.  
  2102. /* ------------------------------------------------------------ */
  2103.  
  2104. /* Convert a time in HH.MMSSss form to decimal hours. */
  2105.  
  2106. double
  2107. U_ToHR(hms)
  2108.     double hms;
  2109.     {
  2110.     double tmp;
  2111.     FLAG isneg = FALSE;
  2112.     int h;
  2113.     int m;
  2114.     int s;
  2115.  
  2116.     if (hms < 0.0) {
  2117.         isneg = TRUE;
  2118.         hms = -hms;
  2119.         }
  2120.  
  2121.     h = hms;
  2122.  
  2123.     hms -= floor(hms);
  2124.     hms *= 100.;
  2125.     m = hms;
  2126.  
  2127.     hms -= floor(hms);
  2128.     hms *= 10000.;
  2129.     s = hms;
  2130.  
  2131.     tmp = h;
  2132.     tmp += (double)m / 60.;
  2133.     tmp += (double)s / 360000.;
  2134.     if (isneg) tmp = -tmp;
  2135.     return(tmp);
  2136.     }
  2137.  
  2138.  
  2139. /* ------------------------------------------------------------ */
  2140.  
  2141. /* Convert the number to a real number, if required. */
  2142.  
  2143. void
  2144. U_ToReal(nptr)
  2145.     struct number *nptr;
  2146.     {
  2147.     int b;
  2148.  
  2149.     if (nptr->type == 'B') {
  2150.         b = nptr->n.b;
  2151.         nptr->n.r = b;
  2152.         nptr->type = 'R';
  2153.         }
  2154.     }
  2155.  
  2156.  
  2157. /* ------------------------------------------------------------ */
  2158.  
  2159. /* Convert the real number date to struct tm according to the current
  2160. date format. */
  2161.  
  2162. void
  2163. U_ToTM(tptr, date)
  2164.     struct tm *tptr;
  2165.     double date;
  2166.     {
  2167.     double d;
  2168.     int i;
  2169.     int f;
  2170.  
  2171.     memset((char *)tptr, NUL, sizeof(*tptr));
  2172.  
  2173.     i = date;
  2174.  
  2175.     date *= 100.;
  2176.     f = date;
  2177.     f %= 100;
  2178.  
  2179.     date -= floor(date);
  2180.     tptr->tm_year = date * 10000. + .5;
  2181.  
  2182.     if (U_FlGet(FL_DMYDATE)) {
  2183.         tptr->tm_mday = i;
  2184.         tptr->tm_mon = f - 1;
  2185.         }
  2186.     else    {
  2187.         tptr->tm_mon = i - 1;
  2188.         tptr->tm_mday = f;
  2189.         }
  2190.     }
  2191.  
  2192.  
  2193. /* ------------------------------------------------------------ */
  2194.  
  2195. /* Convert the number (in radians) to the current trig mode. */
  2196.  
  2197. void
  2198. U_ToTrig(nptr)
  2199.     struct number *nptr;
  2200.     {
  2201.     int mode = U_FlGet(FL_TRIGMODE);
  2202.  
  2203.     if (mode == FLV_DEG) nptr->n.r *= 180.0 / PI;
  2204.     else if (mode == FLV_GRD) nptr->n.r *= 200.0 / PI;
  2205.     }
  2206.  
  2207.  
  2208. /* ------------------------------------------------------------ */
  2209.  
  2210. /* Print the pre-execution trace information. */
  2211.  
  2212. void
  2213. U_Trace1()
  2214.     {
  2215.     char buf[LINEBUFFSIZE];
  2216.  
  2217.     if (!FMakeSys(SYS_TRACE, FALSE)) return;
  2218.  
  2219.     if (cmdptr->desc[9] == 'R' && cmdreg != NULL) {
  2220.         xsprintf(buf, "register %d was %s\n", cmdreg - &m.r[0],
  2221.             U_Fmt(cmdreg));
  2222.         BInsStr(buf);
  2223.         }
  2224.     }
  2225.  
  2226.  
  2227. /* ------------------------------------------------------------ */
  2228.  
  2229. /* Print the post-execution trace information. */
  2230.  
  2231. void
  2232. U_Trace2(retval)
  2233.     char *retval;
  2234.     {
  2235.     char buf[LINEBUFFSIZE];
  2236.     int num;
  2237.  
  2238.     if (!FMakeSys(SYS_TRACE, FALSE)) return;
  2239.  
  2240.     BInsStr(cmdptr->name);
  2241.     if (cmdptr->desc[0] != SP) {
  2242.         if (cmdcmd != CM_NULL) BInsStr(U_FindCmd(cmdcmd)->name);
  2243.         if (cmdind) BInsChar('.');
  2244.         xsprintf(buf, "%d", cmdnum);
  2245.         BInsStr(buf);
  2246.         }
  2247.     BInsStr(": ");
  2248.  
  2249.     if (retval != NULL) {
  2250.         xsprintf(buf, "Error: %s\n", retval);
  2251.         BInsStr(buf);
  2252.         }
  2253.     xsprintf(buf, "L)%s  ", U_Fmt(&m.r[L]));
  2254.     BInsStr(buf);
  2255.     xsprintf(buf, "T)%s  ", U_Fmt(&m.r[T]));
  2256.     BInsStr(buf);
  2257.     xsprintf(buf, "Z)%s  ", U_Fmt(&m.r[Z]));
  2258.     BInsStr(buf);
  2259.     xsprintf(buf, "Y)%s  ", U_Fmt(&m.r[Y]));
  2260.     BInsStr(buf);
  2261.     xsprintf(buf, "X)%s\n", U_Fmt(&m.r[X]));
  2262.     BInsStr(buf);
  2263.  
  2264.     if (cmdptr->desc[9] == 'S') {
  2265.         num = U_FlGet(FL_SUMBASE);
  2266.         xsprintf(buf, "n\t%s\n", U_Fmt(&m.r[num + SUMN]));
  2267.         BInsStr(buf);
  2268.         xsprintf(buf, "x\t%s\n", U_Fmt(&m.r[num + SUMX]));
  2269.         BInsStr(buf);
  2270.         xsprintf(buf, "x^2\t%s\n", U_Fmt(&m.r[num + SUMX2]));
  2271.         BInsStr(buf);
  2272.         xsprintf(buf, "y\t%s\n", U_Fmt(&m.r[num + SUMY]));
  2273.         BInsStr(buf);
  2274.         xsprintf(buf, "y^2\t%s\n", U_Fmt(&m.r[num + SUMY2]));
  2275.         BInsStr(buf);
  2276.         xsprintf(buf, "x*y\t%s\n", U_Fmt(&m.r[num + SUMXY]));
  2277.         BInsStr(buf);
  2278.         }
  2279.     else if (cmdptr->desc[9] == 'R') {
  2280.         xsprintf(buf, "register %d is %s\n", cmdreg - &m.r[0],
  2281.             U_Fmt(cmdreg));
  2282.         BInsStr(buf);
  2283.         }
  2284.     DIncrDisplay();
  2285.     }
  2286.  
  2287.  
  2288. /* ------------------------------------------------------------ */
  2289.  
  2290. /* View interpreted calculator memory. */
  2291.  
  2292. void
  2293. U_View()
  2294.     {
  2295.     char buf[LINEBUFFSIZE];
  2296.     struct flag *fptr;
  2297.     int cnt;
  2298.  
  2299.     if (!FMakeSys(SYS_CALC, TRUE)) return;
  2300.  
  2301.     BInsStr("Stack:\n");
  2302.  
  2303.     xsprintf(buf, "X\t%s\n", U_Fmt(&m.r[X]));
  2304.     BInsStr(buf);
  2305.     xsprintf(buf, "Y\t%s\n", U_Fmt(&m.r[Y]));
  2306.     BInsStr(buf);
  2307.     xsprintf(buf, "Z\t%s\n", U_Fmt(&m.r[Z]));
  2308.     BInsStr(buf);
  2309.     xsprintf(buf, "T\t%s\n", U_Fmt(&m.r[T]));
  2310.     BInsStr(buf);
  2311.     xsprintf(buf, "L\t%s\n", U_Fmt(&m.r[L]));
  2312.     BInsStr(buf);
  2313.  
  2314.     BInsStr(
  2315. "\nFlags (start/bits, value, description (NS = \"not supported\"):\n");
  2316.  
  2317.     for (fptr = flags; fptr < &flags[(int) FL_LAST]; fptr++) {
  2318.         xsprintf(buf, "%d/%d\t%d\t%s\n",
  2319.             fptr->start,
  2320.             fptr->bits,
  2321.             U_FlGet(fptr - flags),
  2322.             fptr->desc);
  2323.         BInsStr(buf);
  2324.         }
  2325.  
  2326.     BInsStr("\nFlags (values):\n");
  2327.  
  2328.     for (cnt = 0; cnt < NUMFLAGS; cnt++) {
  2329.         xsprintf(buf, "%3d - %3d    %04x\n",
  2330.             cnt * 16 + 16,
  2331.             cnt * 16 + 1,
  2332.             m.flags[cnt]);
  2333.         BInsStr(buf);
  2334.         }
  2335.  
  2336.     BInsStr("\nRegisters:\n");
  2337.  
  2338.     for (cnt = 0; cnt < REGCOUNT; cnt++) {
  2339.         xsprintf(buf, "R%02d\t%s\n", cnt, U_Fmt(&m.r[cnt]));
  2340.         BInsStr(buf);
  2341.         }
  2342.  
  2343.     BMoveToStart();
  2344.     DIncrDisplay();
  2345.     }
  2346.  
  2347.  
  2348. /* ------------------------------------------------------------ */
  2349.  
  2350. /* View interpreted summation memory. */
  2351.  
  2352. void
  2353. U_ViewSum()
  2354.     {
  2355.     char buf[LINEBUFFSIZE];
  2356.     int num;
  2357.  
  2358.     if (!FMakeSys(SYS_CALC, TRUE)) return;
  2359.  
  2360.     num = U_FlGet(FL_SUMBASE);
  2361.     xsprintf(buf, "n\t%s\n", U_Fmt(&m.r[num + SUMN]));
  2362.     BInsStr(buf);
  2363.     xsprintf(buf, "x\t%s\n", U_Fmt(&m.r[num + SUMX]));
  2364.     BInsStr(buf);
  2365.     xsprintf(buf, "x^2\t%s\n", U_Fmt(&m.r[num + SUMX2]));
  2366.     BInsStr(buf);
  2367.     xsprintf(buf, "y\t%s\n", U_Fmt(&m.r[num + SUMY]));
  2368.     BInsStr(buf);
  2369.     xsprintf(buf, "y^2\t%s\n", U_Fmt(&m.r[num + SUMY2]));
  2370.     BInsStr(buf);
  2371.     xsprintf(buf, "x*y\t%s\n", U_Fmt(&m.r[num + SUMXY]));
  2372.     BInsStr(buf);
  2373.  
  2374.     BMoveToStart();
  2375.     DIncrDisplay();
  2376.     }
  2377.  
  2378.  
  2379. /* end of CALC.C -- RPN Calculator */
  2380.